home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet Info 1994 March
/
Internet Info CD-ROM (Walnut Creek) (March 1994).iso
/
networking
/
ip
/
ka9q
/
src.arc
/
TELNET.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-08-30
|
8KB
|
374 lines
#include <stdio.h>
#include "global.h"
#include "mbuf.h"
#include "socket.h"
#include "telnet.h"
#include "session.h"
#include "proc.h"
#include "tty.h"
#include "commands.h"
#include "netuser.h"
#define CTLZ 26
extern char Nospace[];
extern char Badhost[];
static void doopt __ARGS((struct telnet *tn,char opt));
static void dontopt __ARGS((struct telnet *tn,char opt));
static void willopt __ARGS((struct telnet *tn,char opt));
static void wontopt __ARGS((struct telnet *tn,char opt));
static void answer __ARGS((struct telnet *tn,int r1,int r2));
int Refuse_echo = 0;
int Unix_line_mode = 0; /* if true turn <cr> to <nl> when in line mode */
#ifdef DEBUG
char *T_options[] = {
"Transmit Binary",
"Echo",
"",
"Suppress Go Ahead",
"",
"Status",
"Timing Mark"
};
#endif
/* Execute user telnet command */
int
dotelnet(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct session *sp;
struct telnet tn;
struct sockaddr_in fsocket;
struct mbuf *bp;
char *cp;
/* Allocate a session descriptor */
if((sp = newsession(argv[1],TELNET)) == NULLSESSION){
printf("Too many sessions\n");
freeargs(argc,argv);
return 1;
}
/* Initialize Telnet protocol descriptor */
memset((char *)&tn,0,sizeof(tn));
tn.output = Curproc;
tn.session = sp; /* Upward pointer */
sp->cb.telnet = &tn; /* Downward pointer */
fsocket.sin_family = AF_INET;
if(argc < 3)
fsocket.sin_port = IPPORT_TELNET;
else
fsocket.sin_port = atoi(argv[2]);
freeargs(argc,argv);
Current = sp;
Mode = CONV_MODE;
if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
printf(Badhost,sp->name);
freesession(sp);
return 1;
}
if((sp->s = socket(AF_INET,SOCK_STREAM,0)) == -1){
printf("Can't create socket\n");
freesession(sp);
return 1;
}
printf("Trying %s...\n",psocket((struct sockaddr *)&fsocket));
if(connect(sp->s,(char *)&fsocket,SOCKSIZE) == -1){
cp = sockerr(sp->s);
printf("Telnet session %u connect failed: %s\n",
(unsigned)(sp-Sessions),cp != NULLCHAR ? cp : "");
freesession(sp);
return 1;
}
printf("Telnet session %u connected to %s\n",
(unsigned)(sp-Sessions),sp->name);
/* Fork off the receiver process */
tn.input = newproc("tel_in",512,tel_input,0,&tn,NULL);
/* Now send whatever's typed on the terminal */
for(;;){
while(sp->input == NULLBUF)
if(pwait(&sp->input) == -1)
goto quit;
bp = dequeue(&sp->input);
/* If we're doing our own echoing and recording is enabled,
* record it
*/
if(!tn.remote[TN_ECHO] && sp->record != NULLFILE)
write_p(sp->record,bp);
if(send_mbuf(sp->s,bp,0,NULLCHAR,0) == -1)
break;
}
quit: close_s(sp->s);
killproc(tn.input);
freesession(sp);
return 0;
}
/* User telnet receive task, started by user telnet command */
void
tel_input(unused,tn1,p)
int unused;
void *tn1;
void *p;
{
int c;
FILE *record;
struct session *sp;
char *cp;
struct mbuf *bp = NULLBUF;
struct telnet *tn;
tn = (struct telnet *)tn1;
sp = tn->session;
while((c = recvchar(sp->s,&bp)) != -1){
/* Suspend output if we're not current */
while(Current != sp || Mode != CONV_MODE)
if(pwait(sp) == -1)
goto quit;
if(uchar(c) == IAC){
/* IAC received, get command sequence */
c = recvchar(sp->s,&bp);
switch(uchar(c)){
case WILL:
willopt(tn,recvchar(sp->s,&bp));
break;
case WONT:
wontopt(tn,recvchar(sp->s,&bp));
break;
case DO:
doopt(tn,recvchar(sp->s,&bp));
break;
case DONT:
dontopt(tn,recvchar(sp->s,&bp));
break;
case IAC: /* Escaped IAC */
putchar(IAC);
if((record = sp->record) != NULLFILE)
putc(IAC,record);
break;
}
} else {
/* Ordinary character */
if(!tn->remote[TN_TRANSMIT_BINARY])
c &= 0x7f;
putchar(c);
if((record = sp->record) != NULLFILE)
putc(c,record);
}
}
quit: /* Close seen from remote host */
free_p(bp);
cp = sockerr(sp->s);
printf("Telnet session %u closed: %s\n", (unsigned)(sp - Sessions),
cp != NULLCHAR ? cp : "EOF");
close_s(sp->s);
killproc(tn->output);
freesession(sp);
}
/* File uploading task */
void
tel_upload(unused,sp1,p)
int unused;
void *sp1;
void *p;
{
struct telnet *tn;
struct session *sp;
struct mbuf *bp;
int c;
char *cp;
sp = (struct session *)sp1;
tn = sp->cb.telnet;
/* Initialize current output buffer */
bp = alloc_mbuf(BUFSIZ);
cp = bp->data;
while((c = getc(sp->upload)) != EOF){
if(bp->cnt >= BUFSIZ-2){
/* If buffer can't take two more characters, flush
* it and get a new one. This allows for a cr/lf
* at the end of the buffer.
*/
send_mbuf(sp->s,bp,0,NULLCHAR,0);
bp = alloc_mbuf(BUFSIZ);
cp = bp->data;
}
/* Copy to output, translating newlines to CR/LF */
if(c == '\n'){
*cp++ = '\r';
bp->cnt++;
}
*cp++ = c;
bp->cnt++;
}
/* Send last buffer, if not empty */
if(bp->cnt != 0)
send_mbuf(sp->s,bp,0,NULLCHAR,0);
else
free_p(bp);
fclose(sp->upload);
sp->upload = NULLFILE;
free(sp->ufile);
sp->ufile = NULLCHAR;
tn->upload = NULLPROC;
}
/* The guts of the actual Telnet protocol: negotiating options */
static
void
willopt(tn,opt)
struct telnet *tn;
char opt;
{
int ack;
#ifdef DEBUG
printf("recv: will ");
if(uchar(opt) <= NOPTIONS)
printf("%s\n",T_options[opt]);
else
printf("%u\n",opt);
#endif
switch(uchar(opt)){
case TN_TRANSMIT_BINARY:
case TN_ECHO:
case TN_SUPPRESS_GA:
if(tn->remote[uchar(opt)] == 1)
return; /* Already set, ignore to prevent loop */
if(uchar(opt) == TN_ECHO){
if(Refuse_echo){
/* User doesn't want to accept */
ack = DONT;
break;
} else
ttysetmode(0); /* Put tty into raw mode */
}
tn->remote[uchar(opt)] = 1;
ack = DO;
break;
default:
ack = DONT; /* We don't know what he's offering; refuse */
}
answer(tn,ack,opt);
}
static void
wontopt(tn,opt)
struct telnet *tn;
char opt;
{
#ifdef DEBUG
printf("recv: wont ");
if(uchar(opt) <= NOPTIONS)
printf("%s\n",T_options[uchar(opt)]);
else
printf("%u\n",uchar(opt));
#endif
if(uchar(opt) <= NOPTIONS){
if(tn->remote[uchar(opt)] == 0)
return; /* Already clear, ignore to prevent loop */
tn->remote[uchar(opt)] = 0;
if(uchar(opt) == TN_ECHO)
ttysetmode(TTY_ECHO|TTY_EDIT); /* Put tty into cooked mode */
}
answer(tn,DONT,opt); /* Must always accept */
}
static void
doopt(tn,opt)
struct telnet *tn;
char opt;
{
int ack;
#ifdef DEBUG
printf("recv: do ");
if(uchar(opt) <= NOPTIONS)
printf("%s\n",T_options[uchar(opt)]);
else
printf("%u\n",uchar(opt));
#endif
switch(uchar(opt)){
#ifdef FUTURE /* Use when local options are implemented */
if(tn->local[uchar(opt)] == 1)
return; /* Already set, ignore to prevent loop */
tn->local[uchar(opt)] = 1;
ack = WILL;
break;
#endif
default:
ack = WONT; /* Don't know what it is */
}
answer(tn,ack,opt);
}
static void
dontopt(tn,opt)
struct telnet *tn;
char opt;
{
#ifdef DEBUG
printf("recv: dont ");
if(uchar(opt) <= NOPTIONS)
printf("%s\n",T_options[uchar(opt)]);
else
printf("%u\n",uchar(opt));
#endif
if(uchar(opt) <= NOPTIONS){
if(tn->local[uchar(opt)] == 0){
/* Already clear, ignore to prevent loop */
return;
}
tn->local[uchar(opt)] = 0;
}
answer(tn,WONT,opt);
}
static void
answer(tn,r1,r2)
struct telnet *tn;
int r1,r2;
{
char s[3];
#ifdef DEBUG
switch(r1){
case WILL:
printf("sent: will ");
break;
case WONT:
printf("sent: wont ");
break;
case DO:
printf("sent: do ");
break;
case DONT:
printf("sent: dont ");
break;
}
if(r2 <= 6)
printf("%s\n",T_options[r2]);
else
printf("%u\n",r2);
#endif
s[0] = IAC;
s[1] = r1;
s[2] = r2;
send(tn->session->s,s,3,0);
}